From 65de2eefe961974ec8c8051d9a5574508bc6d4cf Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 6 Sep 2005 18:25:00 +0000 Subject: [PATCH] The attached patch fixes two problems I ran into with the swiotlb code in unstable (changeset aeaa3c83f6e5). Tested on a dual Opteron x86-64 machine with 4GB of memory and a tg3 modified to only DMA below 2GB. - swiotlb_dma_supported() checked that the device DMA mask was equal or bigger than 4GB, when in fact all that's needed is that the device be able to DMA into the swiotlb aperture (1GB on my AMD x86-64 machine). Some device are actually only 31-bit DMA capable, so this would've tripped them. - On some platforms, PCI unmaps and syncs are nops, so there's no need to keep track of the dma_addr they need after the initial mapping. The DMA API supports this via the DECLARE_PCI_UNMAP_ADDR macros (see Documentation/DMA-mapping.txt). Since the swiotlb code does make us of the dma_addr for swiotlb_unmap_xxx and (more importantly) swiotlb_dma_sync_xxx, we need to define them to something meaningful. Signed-Off-By: Muli Ben-Yehuda --- .../arch/xen/i386/kernel/swiotlb.c | 18 ++++++------- .../include/asm-xen/asm-i386/pci.h | 26 +++++++++++++++++++ .../include/asm-xen/asm-x86_64/pci.h | 23 +++++++++++++--- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c index d72d920376..7d3be682d1 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c @@ -51,7 +51,7 @@ static unsigned long iotlb_nslabs; * swiotlb_sync_single_*, to see if the memory was in fact allocated by this * API. */ -static dma_addr_t iotlb_bus_start, iotlb_bus_mask; +static dma_addr_t iotlb_bus_start, iotlb_bus_end, iotlb_bus_mask; /* Does the given dma address reside within the swiotlb aperture? */ #define in_swiotlb_aperture(a) (!(((a) ^ iotlb_bus_start) & iotlb_bus_mask)) @@ -157,6 +157,7 @@ swiotlb_init_with_default_size (size_t default_size) io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); iotlb_bus_start = virt_to_bus(iotlb_virt_start); + iotlb_bus_end = iotlb_bus_start + bytes; iotlb_bus_mask = ~(dma_addr_t)(bytes - 1); printk(KERN_INFO "Software IO TLB enabled: \n" @@ -165,7 +166,7 @@ swiotlb_init_with_default_size (size_t default_size) " Kernel range: 0x%016lx - 0x%016lx\n", bytes >> 20, (unsigned long)iotlb_bus_start, - (unsigned long)iotlb_bus_start + bytes, + (unsigned long)iotlb_bus_end, (unsigned long)iotlb_virt_start, (unsigned long)iotlb_virt_start + bytes); } @@ -191,6 +192,10 @@ swiotlb_init(void) if (swiotlb) swiotlb_init_with_default_size(64 * (1<<20)); + + printk(KERN_INFO "swiotlb is %sabled%s\n", + (swiotlb ? "en" : "dis"), + (swiotlb_force ? " (forced)" : "")); } static void @@ -424,13 +429,6 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir) } dev_addr = virt_to_bus(map); - - /* - * Ensure that the address returned is DMA'ble - */ - if (address_needs_mapping(hwdev, dev_addr)) - panic("map_single: bounce buffer is not DMA'ble"); - return dev_addr; } @@ -632,7 +630,7 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr) int swiotlb_dma_supported (struct device *hwdev, u64 mask) { - return (mask >= 0xffffffffUL); + return (mask >= (iotlb_bus_end - 1)); } EXPORT_SYMBOL(swiotlb_init); diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h index 707f4da83f..4e521c735d 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h @@ -43,9 +43,33 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); struct pci_dev; +#ifdef CONFIG_SWIOTLB + + /* On Xen we use SWIOTLB instead of blk-specific bounce buffers. */ #define PCI_DMA_BUS_IS_PHYS (0) +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define pci_unmap_addr(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define pci_unmap_len(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + +#else + +/* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (1) + /* pci_unmap_{page,single} is a nop so... */ #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) @@ -54,6 +78,8 @@ struct pci_dev; #define pci_unmap_len(PTR, LEN_NAME) (0) #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) +#endif + /* This is always fine. */ #define pci_dac_dma_supported(pci_dev, mask) (1) diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pci.h b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pci.h index 119ccdfb72..9181f47e9d 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pci.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pci.h @@ -63,6 +63,25 @@ extern int iommu_setup(char *opt); extern int iommu_sac_force; #define pci_dac_dma_supported(pci_dev, mask) (!iommu_sac_force) +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define pci_unmap_addr(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define pci_unmap_len(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + +#elif defined(CONFIG_SWIOTLB) + +#define PCI_DMA_BUS_IS_PHYS 0 + +#define pci_dac_dma_supported(pci_dev, mask) 1 + #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ dma_addr_t ADDR_NAME; #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ @@ -79,9 +98,7 @@ extern int iommu_sac_force; #else /* No IOMMU */ -/* On Xen we use SWIOTLB instead of blk-specific bounce buffers. */ -#define PCI_DMA_BUS_IS_PHYS (0) - +#define PCI_DMA_BUS_IS_PHYS 1 #define pci_dac_dma_supported(pci_dev, mask) 1 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) -- 2.30.2